package com.allwees.bs.module.scm.service.impl;

import com.allwees.bs.core.modelbase.function.FunctionValidatable;
import com.allwees.bs.core.modelbase.transform.ObjectTransformFactory;
import com.allwees.bs.core.modelbase.transform.TransformFactoryStrategy;
import com.allwees.bs.module.base.service.impl.BoServiceImpl;
import com.allwees.bs.module.lms.dao.LogisticsWaybillDao;
import com.allwees.bs.module.lms.entity.LogisticsWaybill;
import com.allwees.bs.module.oms.bo.OmsOrderItemShippingMqBo;
import com.allwees.bs.module.oms.constant.EShippingType;
import com.allwees.bs.module.ops.entity.WareHouseAddress;
import com.allwees.bs.module.ops.service.WareHouseAddressService;
import com.allwees.bs.module.scm.bo.ScmOrderShippingBo;
import com.allwees.bs.module.scm.dao.ScmOrderSkuShippedLogDao;
import com.allwees.bs.module.scm.dao.ScmPickOrderSkuDao;
import com.allwees.bs.module.scm.entity.ScmAllocateOrderSku;
import com.allwees.bs.module.scm.entity.ScmOrderSkuShippedLog;
import com.allwees.bs.module.scm.entity.ScmPickOrderSku;
import com.allwees.bs.module.scm.mq.event.SupplierShippedMqEvent;
import com.allwees.bs.module.scm.req.PickOrderSkuBackToAllocateReq;
import com.allwees.bs.module.scm.req.PickOrderSkuShippingReq;
import com.allwees.bs.module.scm.service.ScmAllocateOrderSkuService;
import com.allwees.bs.module.scm.service.ScmPickOrderSkuService;
import com.allwees.bs.module.scm.service.ScmShippingOrderService;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.mq.rabbitmq.MqUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * scm 拣货
 *
 * @author mouhn
 * @since 2019-12-31 15:38
 */
@Slf4j
@Service
public class ScmPickOrderSkuServiceImpl extends BoServiceImpl<ScmPickOrderSkuDao, ScmPickOrderSku> implements ScmPickOrderSkuService {

    @Autowired
    private ScmAllocateOrderSkuService allocateOrderSkuService;
    @Autowired
    private ScmShippingOrderService shippingOrderService;
    @Autowired
    private WareHouseAddressService wareHouseAddressService;
    @Autowired
    private ScmOrderSkuShippedLogDao orderSkuShippedLogDao;
    @Autowired
    private LogisticsWaybillDao logisticsWaybillDao;

    @Override
    public boolean create(List<ScmAllocateOrderSku> allocateOrderSkus) {
        ObjectTransformFactory<ScmAllocateOrderSku, ScmPickOrderSku> factory = TransformFactoryStrategy.strategy(ScmAllocateOrderSku.class, ScmPickOrderSku.class);

        for (ScmAllocateOrderSku allocateOrderSku : allocateOrderSkus) {
        	baseMapper.create(factory.transform(allocateOrderSku));
        }
        return true;
    }

    @Override
    @Transactional
    public int backToAllocate(PickOrderSkuBackToAllocateReq req) {
        int successSum = 0;

        for (String uuid : req.getPickOrderSkuUuids()) {

            ScmPickOrderSku pickOrderSku = findByUuid(uuid);
            pickOrderSku.assertStatus(EStatus.NORMAL, EStatus.SELLOUT);

            baseMapper.deleteByUuid(uuid);

            allocateOrderSkuService.backFromPick(pickOrderSku.getAllocateOrderSkuUuid());

            successSum++;
        }
        return successSum;
    }

    @Override
    @Transactional
    public void shipping(EShippingType shippingType, PickOrderSkuShippingReq req) {
        Date shippingAt = new Date();

        List<ScmPickOrderSku> pickOrderSkus = baseMapper.findByUuids(req.getPickOrderSkuUuids());

        for (ScmPickOrderSku pickOrderSku : pickOrderSkus) {
            pickOrderSku.assertStatus(EStatus.NORMAL);
            pickOrderSku.setEStatus(EStatus.SHIPPED);

            pickOrderSku.setShippingAt(shippingAt);
            updateByUuid(pickOrderSku);

            _saveShippingLog(pickOrderSku);

            _saveLogisticsWaybill(pickOrderSku, req);
        }

        WareHouseAddress wareHouseAddress = wareHouseAddressService.findByUuid(req.getReceiveAddressUuid());

        ScmOrderShippingBo shippingBo = new ScmOrderShippingBo()
                .setShippingType(shippingType)
                .setExpressCode(req.getExpressCode())
                .setLogisticsType(req.getLogisticsType())
                .setShippingUserUuid(req.getBranchUserUuid())
                .setLogisticsUuid(req.getLogisticsUuid())
                .setReserveDate(req.getReserveDate())
                .setReserveRange(req.getReserveRange())
                .setReceiveAddressUuid(req.getReceiveAddressUuid())
                .setWareHouseUuid(wareHouseAddress != null ? wareHouseAddress.getWareHouseUuid() : "")
                .setShippingAt(shippingAt)
                .setPickOrderSkus(baseMapper.findByUuids(req.getPickOrderSkuUuids()));

        shippingOrderService.create(shippingBo);

        Set<String> orderItemUuids = pickOrderSkus.stream().map(ScmPickOrderSku::getOrderItemUuid).collect(Collectors.toSet());
        MqUtil.send(new SupplierShippedMqEvent(new OmsOrderItemShippingMqBo(orderItemUuids, shippingType, req.getExpressCode())));
    }

    @Override
	public Integer _updateStatus(Set<String> pickOrderSkuUuids, EStatus status, FunctionValidatable<ScmPickOrderSku> validatable) {
        int successSum = 0;
        List<ScmPickOrderSku> pickOrderSkus = findByUuids(pickOrderSkuUuids);

        for (ScmPickOrderSku pickOrderSku : pickOrderSkus) {

            validatable.validate(pickOrderSku);

            ScmPickOrderSku update = new ScmPickOrderSku();
            update.setUuid(pickOrderSku.getUuid());
            update.setEStatus(status);
            if (updateByUuid(update)) {
                successSum++;
            }
        }
        return successSum;
    }

    private void _saveShippingLog(ScmPickOrderSku pickOrderSku) {
        ScmOrderSkuShippedLog orderSkuShippedLog = new ScmOrderSkuShippedLog()
                .setOrderItemNo(pickOrderSku.getOrderItemNo())
                .setOrderItemUuid(pickOrderSku.getOrderItemUuid())
                .setOrderNo(pickOrderSku.getOrderNo())
                .setOrderUuid(pickOrderSku.getOrderUuid())
                .setSkuNo(pickOrderSku.getSkuNo())
                .setSkuUuid(pickOrderSku.getSkuUuid())
                .setQuantity(pickOrderSku.getShippingQuantity())
                .setPickOrderSkuUuid(pickOrderSku.getUuid());
        orderSkuShippedLogDao.create(orderSkuShippedLog);
    }

    private void _saveLogisticsWaybill(ScmPickOrderSku pickOrderSku, PickOrderSkuShippingReq req) {
        LogisticsWaybill waybill = new LogisticsWaybill();
        waybill.setOrderItemUuid(pickOrderSku.getOrderItemUuid());
        waybill.setOrderUuid(pickOrderSku.getOrderUuid());
        waybill.setShippingDate(new Date());
        waybill.setExpressCode(req.getExpressCode());
        logisticsWaybillDao.insert(waybill);
    }
}
